package com.rpcLearning.client;

import com.rpcLearning.proto.Request;
import com.rpcLearning.proto.Response;
import com.rpcLearning.proto.ServiceDescriptor;
import com.rpcLearning.transport.TransportClient;
import com.rpclearnging.codec.Decoder;
import com.rpclearnging.codec.Encoder;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.IOUtils;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;

/**
 * @author:zyh
 * @Time:2021-03-17-21:28
 * @email:1269231889@qq.com 调用远程服务的代理类
 */
@Slf4j
public class RemoteInvoker implements InvocationHandler {
    private Class cla;
    private Encoder encoder;
    private Decoder decoder;
    private TransportSelector selector;

    public RemoteInvoker(Class cla,
                         Encoder encoder,
                         Decoder decoder,
                         TransportSelector selector) {
        this.cla = cla;
        this.encoder = encoder;
        this.decoder = decoder;
        this.selector = selector;
    }

    @Override
    public Object invoke(Object proxy,
                         Method method,
                         Object[] args) throws Throwable {
        Request request = new Request();
        request.setService(ServiceDescriptor.from(cla,method));
        request.setParameters(args);

        Response response = invokeRemote(request);
        if(response==null||response.getStatus()!=0){
            throw new IllegalStateException("失败");
        }
        log.info("response data : {}",response.getData());
        //不是返回response数据，而是返回其中的类对象
        return response.getData();
    }

    private Response invokeRemote(Request request) {
        Response resp = null;
        TransportClient client = null;
        try{
            client = selector.select();
            byte[] outBytes = encoder.encode(request);
            InputStream recive = client.write(new ByteArrayInputStream(outBytes));
            byte[] inBytes = IOUtils.readFully(recive, recive.available());
            //response赋值
            resp = decoder.decoder(inBytes, Response.class);

        } catch (IOException e) {
            log.warn(e.getMessage(), e);
            resp.setStatus(1);
            resp.setMessage("RpcClient got error :" + e.getMessage() + " ： ");
        } finally {
            if (client != null){
                selector.release(client);
            }
        }
        return resp;
    }
}
